﻿/*
 * Created by SharpDevelop.
 * User: MyWife
 * Date: 7/26/2010
 * Time: 4:33 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Drawing;
using System.Windows.Forms;
using popLib;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.IO;
using popLib.CustomeControl;
using System.Collections;

namespace popLib.ExtensionClass
{
	/// <summary>
	/// Description of FormValidation.
	/// </summary>
    public class FormValidation
    {
        ErrorProvider ERROR_PROVIDER;
        List<Control> CONTROL_TO_VALIDATE;
        List<Control> CONTROL_TO_HANDLE;
        List<Control> CONTROL_TO_HANDLE_EXCEPT;
        List<Control> CONTAINER_TO_HANDLE;
        List<Control> CONTROL_TO_LOCK;
        object FORM_TO_VALIDATE;

        private FormLanguage _Language;
        public FormLanguage Language
        {
            get { return _Language; }
            set
            {
                _Language = value;
                switch (_Language)
                {
                    case FormLanguage.English:
                        ValidateMessage = new ValidateMessageSet().English();
                        break;
                    case FormLanguage.Vietnamese:
                        ValidateMessage = new ValidateMessageSet().Vietnamese();
                        break;
                    case FormLanguage.Custom:
                        if (ValidateMessage == null)
                            ValidateMessage = new ValidateMessageSet().English();                        
                        break;
                }
            }
        }
        
        public int MyProperty { get; set; }
        public ValidateMessageSet ValidateMessage { get; set; }

        public bool IsFormValidated { get; set; }
        public bool AutoValidate { get; set; }
        public bool AutoClearInput { get; set; }
        public bool AutoPerformClickAdd { get; set; }
        public bool AutoPerformClickUpdate { get; set; }
        public bool AutoPerformClickCancel { get; set; }
        public bool FormValueChanged { get; set; }
        public bool IsValidateForm { get; set; }


        public FormState CurrentFormState { get; set; }
        public Button ButtonAdd { get; set; }
        public Button ButtonUpdate { get; set; }
        public Button ButtonDispose { get; set; }
        public Button ButtonConfirm { get; set; }
        public Button ButtonSave { get; set; }
        public Button ButtonCancel { get; set; }
        public Button ButtonPrint { get; set; }

        public delegate void FormStateChangeEvent(FormState state);
        public event FormStateChangeEvent FormStateChanged;
                
        public event FormStateChangeEvent FormStateBeforeChanged;

        public FormValidation(Form formToValidate)
        {
            IsValidateForm = true;
            FORM_TO_VALIDATE = formToValidate;

            InitProperties();
        }

        public FormValidation(UserControl formToValidate)
        {
            IsValidateForm = false;
            FORM_TO_VALIDATE = formToValidate;

            InitProperties();
        }

        private void InitProperties()
        {
            CONTROL_TO_VALIDATE = new List<Control>();
            CONTROL_TO_HANDLE = new List<Control>();
            CONTROL_TO_HANDLE_EXCEPT = new List<Control>();
            CONTAINER_TO_HANDLE = new List<Control>();
            CONTROL_TO_LOCK = new List<Control>();
            ERROR_PROVIDER = new ErrorProvider();

            IsFormValidated = false;
            AutoValidate = true;
            AutoClearInput = true;
            AutoPerformClickAdd = false;
            AutoPerformClickUpdate = false;
            AutoPerformClickCancel = false;
            FormValueChanged = false;
            if (ValidateMessage == null) ValidateMessage = new ValidateMessageSet().English();
        }

        #region NAVIGATE FORM FUNCTIONS

        public event ClearInputEvent ExecuteClearInput;
        public delegate void ClearInputEvent(CancelEventArgs e);

        public delegate void EnableEditEvent(bool enable);
        private EnableEditEvent _editingEnabled;

        public event EnableEditEvent EditingEnabled
        {
            add
            {
                _editingEnabled += value;
            }

            remove
            {
                if (value != null)
                    _editingEnabled -= value;
                else
                    _editingEnabled = null;
            }
        }


        public enum FormState { Ready, CreateNew, UpdateCurrent }


        /// <summary>
        /// Init form navigate buttons
        /// </summary>
        /// <param name="btn_add"></param>
        /// <param name="ButtonUpdate"></param>
        /// <param name="btn_dispose"></param>
        /// <param name="btn_save"></param>
        /// <param name="btn_cancel"></param>
        public void InitNavigatorForm(Button btn_add, Button btn_update, Button btn_dispose, Button btn_save, Button btn_cancel, Button btn_confirm, Button btn_print)
        {
            ButtonAdd = btn_add;
            ButtonUpdate = btn_update;
            ButtonDispose = btn_dispose;
            ButtonSave = btn_save;
            ButtonCancel = btn_cancel;
            ButtonConfirm = btn_confirm;
            ButtonPrint = btn_print;

            ButtonAdd.Click += delegate(object sender, EventArgs e)
            {
                if (AutoPerformClickAdd) ChangeState(FormState.CreateNew);
            };

            ButtonUpdate.Click += delegate(object sender, EventArgs e)
            {
                if (AutoPerformClickUpdate) ChangeState(FormState.UpdateCurrent);
            };

            ButtonCancel.Click += delegate(object sender, EventArgs e)
            {
                if (AutoPerformClickCancel) ChangeState(FormState.Ready);
            };

            //init form state to ready
            ChangeState(FormState.Ready);

            //int all handle control will be check change
            InitCheckChangeHandleControl();
        }

        /// <summary>
        /// Add controls to handle list in order to disable or enabe when user change state of form from view to edit/insert        
        /// </summary>
        /// <param name="control"></param>
        public void AddHandleControl(Control control)
        {
            CONTROL_TO_HANDLE.Add(control);
        }

        public void AddHandleControlExceptLock(List<Control> lockControls, List<Control> unlockControls = null)
        {
            if (lockControls != null)
            {
                foreach (var control in lockControls)
                {
                    AddHandleControlExceptLock(control, true);
                }
            }

            if (unlockControls != null)
            {
                foreach (var control in unlockControls)
                {
                    AddHandleControlExceptLock(control, false);
                }
            }

        }

        public void AddHandleControlExceptLock(Control control, bool isLock)
        {
            LockInput(control, isLock);
            CONTROL_TO_HANDLE_EXCEPT.Add(control);
        }

        public void AddHandleControlExceptLock(Control control)
        {
            CONTROL_TO_HANDLE_EXCEPT.Add(control);
        }

        /// <summary>
        /// Remove control from handle list
        /// </summary>
        /// <param name="control"></param>
        public void RemoveHandleControl(Control control)
        {
            if (CONTROL_TO_HANDLE.Contains(control))
            {
                CONTROL_TO_HANDLE.Remove(control);
            }
        }

        /// <summary>
        /// Add container control that contain child need to handle
        /// </summary>
        /// <param name="control"></param>
        public void AddHandleContainer(Control control)
        {
            CONTAINER_TO_HANDLE.Add(control);
        }

        /// <summary>
        /// Remove container control from list
        /// </summary>
        /// <param name="control"></param>
        public void RemoveHandleContainer(Control control)
        {
            if (CONTAINER_TO_HANDLE.Contains(control))
            {
                CONTAINER_TO_HANDLE.Remove(control);
            }
        }

        /// <summary>
        /// Add controls to handle list in order to disable or enabe when user change state of form from view to edit/insert        
        /// </summary>
        /// <param name="control"></param>
        public void AddLockControl(Control control)
        {
            CONTROL_TO_LOCK.Add(control);
        }

        /// <summary>
        /// Remove control from handle list
        /// </summary>
        /// <param name="control"></param>
        public void RemoveLockControl(Control control)
        {
            if (CONTROL_TO_LOCK.Contains(control))
            {
                CONTROL_TO_LOCK.Remove(control);
            }
        }



        /// <summary>
        /// Change form state to Ready if current state is CreateNew
        /// Or change state to ItemSelected if current state is not CreateNew
        /// </summary>
        public void PerformClickSave()
        {
            ChangeState(FormState.Ready);
        }

        /// <summary>
        /// Change form state to ready and clear all input
        /// </summary>
        public void PerformClickRemove()
        {
            ChangeState(FormState.Ready);
        }

        /// <summary>
        /// Change state for form, disable or enable button as well as clear appropriate input
        /// </summary>
        /// <param name="state"></param>
        public void ChangeState(FormState state)
        {
            //raise event
            if (FormStateBeforeChanged != null)
            {
                FormStateBeforeChanged(state);
            }

            switch (state)
            {
                case FormState.Ready:
                    SetEnableButton(new Button[] { ButtonSave, ButtonCancel }, false);
                    SetEnableButton(new Button[] { ButtonPrint, ButtonUpdate, ButtonDispose, ButtonAdd, ButtonConfirm }, true);
                    LockInput(true);
                    if (CurrentFormState == FormState.CreateNew) DoClearInput();

                    // fired an editing enable event
                    if (_editingEnabled != null)
                        _editingEnabled(false);
                    break;
                case FormState.CreateNew:
                    SetEnableButton(new Button[] { ButtonUpdate, ButtonDispose, ButtonAdd }, false);
                    SetEnableButton(new Button[] { ButtonPrint, ButtonConfirm, ButtonSave, ButtonCancel }, true);
                    LockInput(false);
                    DoClearInput();
                    FormValueChanged = false;

                    // fired an editing enable event
                    if (_editingEnabled != null)
                        _editingEnabled(true);

                    break;
                case FormState.UpdateCurrent:
                    SetEnableButton(new Button[] { ButtonUpdate, ButtonDispose, ButtonAdd }, false);
                    SetEnableButton(new Button[] { ButtonPrint, ButtonConfirm, ButtonSave, ButtonCancel }, true);
                    LockInput(false);
                    FormValueChanged = false;

                    // fired an editing enable event
                    if (_editingEnabled != null)
                        _editingEnabled(true);

                    break;
            }

            //raise event
            if (FormStateChanged != null)
            {
                FormStateChanged(state);
            }

            CurrentFormState = state;

            Invalidate();
        }

        private void SetEnableButton(Button[] buttons, bool isEnable)
        {
            foreach (var item in buttons)
            {
                if (item != null) item.Enabled = isEnable;
            }
        }

        /// <summary>
        /// Disable all Control from CONTROL_TO_HANDLE and all children of CONTAINER_TO_HANDLE
        /// </summary>
        /// <param name="isLock"></param>
        public void LockInput(bool isLock)
        {
            foreach (Control control in CONTROL_TO_HANDLE)
            {
                if (CONTROL_TO_HANDLE_EXCEPT.Contains(control)) continue;
                LockInput(control, isLock);
            }

            foreach (Control container in CONTAINER_TO_HANDLE)
            {
                foreach (Control control in container.Controls)
                {
                    if (CONTROL_TO_HANDLE_EXCEPT.Contains(control)) continue;
                    LockInput(control, isLock);
                }
            }

            foreach (Control control in CONTROL_TO_LOCK)
            {
                if (CONTROL_TO_HANDLE_EXCEPT.Contains(control)) continue;
                LockInput(control, isLock);
            }
        }


        Hashtable dgvAllowUserToAddRows = new Hashtable();
        Hashtable dgvAllowUserToDeleteRows = new Hashtable();
        Hashtable dgvColumnReadonly = new Hashtable();

        public void LockInput(Control control, bool isLock)
        {
            ControlType type = FormLib.getControlType(control);
            switch (type)
            {
                case ControlType.TextBox: ((TextBox)control).ReadOnly = isLock; break;
                case ControlType.DataGridView:
                    if ( dgvAllowUserToAddRows.ContainsKey(control.Name) == false )
                    {
                        dgvAllowUserToAddRows.Add(control.Name, ((DataGridView)control).AllowUserToAddRows );
                        dgvAllowUserToDeleteRows.Add(control.Name, ((DataGridView)control).AllowUserToDeleteRows);

                        int index = 0;
                        foreach (DataGridViewColumn item in ((DataGridView)control).Columns)
                        {
                            if (item.ReadOnly == false) continue;
                            dgvColumnReadonly.Add(control.Name + "." + item.Name +"."+ (index++), item.ReadOnly);
                        }
                    }

                    ((DataGridView)control).ReadOnly = isLock;

                    if (isLock)
                    {
                        ((DataGridView)control).AllowUserToAddRows = !isLock;
                        ((DataGridView)control).AllowUserToDeleteRows = !isLock;
                    }
                    else
                    {
                        if ( (bool)dgvAllowUserToAddRows[control.Name] == true ) ((DataGridView)control).AllowUserToAddRows = !isLock;
                        if ((bool)dgvAllowUserToDeleteRows[control.Name] == true) ((DataGridView)control).AllowUserToDeleteRows = !isLock;

                        int index = 0;
                        foreach (DataGridViewColumn item in ((DataGridView)control).Columns)
                        {
                            if (dgvColumnReadonly.ContainsKey(control.Name + "." + item.Name + "." + (index++)))
                            {
                                item.ReadOnly = true;
                            }
                        }
                    }


                    break;
                case ControlType.None:
                    control.Enabled = !isLock;
                    if (control.GetType().Name.Contains("ExComboBox"))
                        ((ExComboBox)control).ReadOnly = isLock;
                    if (control.GetType().Name.Contains("ExDateTimePicker"))
                        ((ExDateTimePicker)control).ReadOnly = isLock;
                    //if (control.GetType().Name.Contains("AutoCompleteComboBox"))
                    //    ((AutoCompleteComboBox)control).ReadOnly = isLock;
                    break;
                case ControlType.Label: control.Enabled = true; break;
                default: control.Enabled = !isLock; break;
            }
        }

        public void InitCheckChangeHandleControl()
        {
            foreach (Control control in CONTROL_TO_HANDLE)
            {
                CheckChangeControl(control);
            }

            foreach (Control control in CONTAINER_TO_HANDLE)
            {
                Control[] controls = FormLib.getChildControlList(control);
                foreach (Control child in controls)
                {
                    CheckChangeControl(child);
                }
            }
        }

        public void CheckChangeControl(Control control)
        {
            switch (FormLib.getControlType(control))
            {
                case ControlType.TextBox:
                    ((TextBox)control).TextChanged += delegate { FormValueChanged = true; };
                    break;
                case ControlType.ComboBox:
                    ((ComboBox)control).SelectedIndexChanged += delegate { FormValueChanged = true; };
                    break;
                case ControlType.CheckedListBox:
                    ((CheckedListBox)control).ItemCheck += delegate { FormValueChanged = true; };
                    break;
                case ControlType.ListBox:
                    ((ListBox)control).SelectedIndexChanged += delegate { FormValueChanged = true; };
                    break;
                case ControlType.CheckBox:
                    ((CheckBox)control).CheckedChanged += delegate { FormValueChanged = true; };
                    break;
                case ControlType.DateTimePicker:
                    ((DateTimePicker)control).ValueChanged += delegate { FormValueChanged = true; };
                    break;
                case ControlType.NumericUpDown:
                    ((NumericUpDown)control).ValueChanged += delegate { FormValueChanged = true; };
                    break;
            }
        }

        /// <summary>
        /// Execute remove all input from CONTROL_TO_HANDLE and all children of CONTAINER_TO_HANDLE
        /// if ExecuteClearInput event is set call event
        /// </summary>
        public void ClearInput()
        {
            foreach (Control control in CONTROL_TO_HANDLE)
            {
                ClearInput(control);
            }

            foreach (Control control in CONTAINER_TO_HANDLE)
            {
                Control[] controls = FormLib.getChildControlList(control);
                foreach (Control child in controls)
                {
                    ClearInput(child);
                }
            }
        }

        private void DoClearInput()
        {
            if (!AutoClearInput) return;

            if (ExecuteClearInput != null)
            {
                CancelEventArgs e = new CancelEventArgs();
                ExecuteClearInput(e);

                if (e.Cancel)
                    return;
            }

            ClearInput();
        }

        /// <summary>
        /// Clear data/value from control
        /// </summary>
        /// <param name="control"></param>
        public void ClearInput(Control control)
        {
            switch (FormLib.getControlType(control))
            {
                case ControlType.TextBox:
                    control.Text = "";
                    break;
                case ControlType.ComboBox:
                    if (((ComboBox)control).Items.Count > 0)
                        ((ComboBox)control).SelectedIndex = 0;
                    break;
                case ControlType.CheckedListBox:
                    ((CheckedListBox)control).ClearSelected();
                    break;
                case ControlType.ListBox:
                    ((ListBox)control).ClearSelected();
                    break;
                case ControlType.CheckBox:
                    ((CheckBox)control).Checked = false;
                    break;
                case ControlType.DateTimePicker:
                    ((DateTimePicker)control).Value = DateTime.Now;
                    break;
            }
        }
        #endregion

        #region ALL VALIDATION FUNCTIONS
        /// <summary>
        /// Validate each control and return result
        /// </summary>
        /// <returns></returns>
        public bool Validate()
        {
            IsFormValidated = true;
            bool isAutoValidate = AutoValidate;
            AutoValidate = true;

            foreach (Control control in CONTROL_TO_VALIDATE)
            {
                if (control.Enabled)
                {
                    control.Focus();
                    if (IsValidateForm)
                        ((Form)FORM_TO_VALIDATE).Validate();
                    else ((UserControl)FORM_TO_VALIDATE).Validate();
                }
                else
                {
                    ERROR_PROVIDER.SetError(control, null);
                }
            }

            AutoValidate = isAutoValidate;

            return IsFormValidated;
        }

        /// <summary>
        /// Clear all validate error
        /// </summary>
        public void Invalidate()
        {
            ERROR_PROVIDER.Clear();
        }




        /// <summary>
        /// Remove all validation event for this control
        /// </summary>
        /// <param name="control"></param>
        public void RemoveValidate(Control control)
        {
            if (CONTROL_TO_VALIDATE.Contains(control))
            {
                CONTROL_TO_VALIDATE.Remove(control);
            }
            FormLib.RemoveEventFromControl(control, "Validating");
        }


        #region ValidateGroupRadioButton
        /// <summary>
        /// Validate group of RadioButton that located in one container
        /// </summary>
        /// <param name="container">Container control could be Panel, FlowLayoutPanel, GroupBox</param>
        public void ValidateGroupRadioButton(Control container)
        {
            ValidateGroupRadioButton(container, null);
        }

        /// <summary>
        /// Validate group of RadioButton that located in one container
        /// </summary>
        /// <param name="container">Container control could be Panel, FlowLayoutPanel, GroupBox</param>
        /// <param name="message">Custom message if message is not null or blank</param>
        public void ValidateGroupRadioButton(Control container, string message)
        {
            CONTROL_TO_VALIDATE.Add(container);

            container.Validating += delegate(object sender, CancelEventArgs e)
            {
                if (!AutoValidate) return;
                Control senderControl = (Control)sender;

                int checkedCounter = 0;
                foreach (RadioButton item in senderControl.Controls)
                {
                    if (item.Checked) checkedCounter++;
                }

                if (checkedCounter < 1)
                {
                    if (!StringLib.isValid(message))
                        message = ValidateMessage.ValidateGroupRadioButton;

                    ERROR_PROVIDER.SetError(senderControl, message);
                    IsFormValidated = false;
                }
                else
                {
                    ERROR_PROVIDER.SetError(senderControl, null);
                }
            };
        }
        #endregion

        #region ValidateGroupCheckBox
        /// <summary>
        /// Validate group of CheckBox that located in one container and specify total of CheckBox must be checked
        /// </summary>
        /// <param name="container">Container control could be Panel, FlowLayoutPanel, GroupBox</param>
        /// <param name="minimumChecked">Total checked box must be checked</param>
        public void ValidateGroupCheckBox(Control container, int minimumChecked)
        {
            ValidateGroupCheckBox(container, minimumChecked, null);
        }


        /// <summary>
        /// Validate group of CheckBox that located in one container and specify total of CheckBox must be checked
        /// </summary>
        /// <param name="container">Container control could be Panel, FlowLayoutPanel, GroupBox</param>
        /// <param name="minimumChecked">Total checked box must be checked</param>
        /// <param name="message">Custom message if message is not null or blank</param>
        public void ValidateGroupCheckBox(Control container, int minimumChecked, string message)
        {
            CONTROL_TO_VALIDATE.Add(container);

            container.Validating += delegate(object sender, CancelEventArgs e)
            {
                if (!AutoValidate) return;
                Control senderControl = (Control)sender;

                int checkedCounter = 0;
                foreach (CheckBox item in senderControl.Controls)
                {
                    if (item.Checked) checkedCounter++;
                }

                if (checkedCounter < minimumChecked)
                {

                    if (!StringLib.isValid(message))
                        message = ValidateMessage.ValidateGroupCheckBox;
                    message = message.Replace("[MIN]", minimumChecked + "");

                    ERROR_PROVIDER.SetError(senderControl, message);
                    IsFormValidated = false;
                }
                else
                {
                    ERROR_PROVIDER.SetError(senderControl, null);
                }
            };
        }
        #endregion

        #region ValidateCheckedListBox
        /// <summary>
        /// Validate CheckedListBox and specify total of items must be checked
        /// </summary>
        /// <param name="control">CheckedListBox to validate</param>
        /// <param name="minimumChoice">Total of items must be checked</param>
        public void ValidateCheckedListBox(CheckedListBox control, int minimumChoice)
        {
            ValidateCheckedListBox(control, minimumChoice, null);
        }

        /// <summary>
        /// Validate CheckedListBox and specify total of items must be checked
        /// </summary>
        /// <param name="control">CheckedListBox to validate</param>
        /// <param name="minimumChoice">Total of items must be checked</param>
        /// <param name="message">Custom message if message is not null or blank</param>
        public void ValidateCheckedListBox(CheckedListBox control, int minimumChoice, string message)
        {
            CONTROL_TO_VALIDATE.Add(control);

            control.Validating += delegate(object sender, CancelEventArgs e)
            {
                if (!AutoValidate) return;
                CheckedListBox senderControl = (CheckedListBox)sender;
                if (senderControl.CheckedIndices.Count < minimumChoice)
                {

                    if (!StringLib.isValid(message))
                        message = ValidateMessage.ValidateCheckedListBox;
                    message = message.Replace("[MIN]", minimumChoice + "");

                    ERROR_PROVIDER.SetError(senderControl, message);
                    IsFormValidated = false;
                }
                else
                {
                    ERROR_PROVIDER.SetError(senderControl, null);
                }
            };
        }
        #endregion

        #region ValidateListBox
        /// <summary>
        /// Validate ListBox by specifing total items must be selected
        /// </summary>
        /// <param name="control">ListBox to validate</param>
        /// <param name="minimumSelection">Total of item must be selected</param>
        public void ValidateListBox(ListBox control, int minimumSelection)
        {
            ValidateListBox(control, minimumSelection, null);
        }

        /// <summary>
        /// Validate ListBox by specifing total items must be selected
        /// </summary>
        /// <param name="control">ListBox to validate</param>
        /// <param name="minimumSelection">Total of item must be selected</param>
        /// <param name="message">Custom message if message is not null or blank</param>
        public void ValidateListBox(ListBox control, int minimumSelection, string message)
        {
            CONTROL_TO_VALIDATE.Add(control);

            if (minimumSelection > 1)
                control.SelectionMode = SelectionMode.MultiExtended;

            control.Validating += delegate(object sender, CancelEventArgs e)
            {
                if (!AutoValidate) return;
                ListBox senderControl = (ListBox)sender;
                if (senderControl.SelectedIndices.Count < minimumSelection)
                {

                    if (!StringLib.isValid(message))
                        message = ValidateMessage.ValidateListBox;
                    message = message.Replace("[MIN]", minimumSelection + "");

                    ERROR_PROVIDER.SetError(senderControl, message);
                    IsFormValidated = false;
                }
                else
                {
                    ERROR_PROVIDER.SetError(senderControl, null);
                }
            };
        }
        #endregion

        #region ValidateCombobox
        /// <summary>
        /// Validate Combobox must have one item selected
        /// </summary>
        /// <param name="control">Combobox to validate</param>
        /// <param name="defaultIndex">True if ignor the first item</param>
        public void ValidateCombobox(ComboBox control, bool defaultIndex)
        {
            ValidateCombobox(control, defaultIndex, null);
        }

        /// <summary>
        /// Validate Combobox must have one item selected
        /// </summary>
        /// <param name="control">Combobox to validate</param>
        /// <param name="defaultIndex">True if ignor the first item</param>
        /// <param name="message">Custom message if message is not null or blank</param>
        public void ValidateCombobox(ComboBox control, bool defaultIndex, string message)
        {
            CONTROL_TO_VALIDATE.Add(control);

            control.Validating += delegate(object sender, CancelEventArgs e)
            {
                if (!AutoValidate) return;
                ComboBox senderControl = (ComboBox)sender;

                if (!StringLib.isValid(message))
                    message = ValidateMessage.ValidateCombobox;

                if (senderControl.SelectedIndex < 0)
                {
                    ERROR_PROVIDER.SetError(senderControl, message);
                    IsFormValidated = false;
                }
                else if (defaultIndex && senderControl.SelectedIndex == 0)
                {
                    ERROR_PROVIDER.SetError(senderControl, message);
                    IsFormValidated = false;
                }
                else
                {
                    ERROR_PROVIDER.SetError(senderControl, null);
                }
            };
        }
        #endregion

        #region ValidateBirthday

        /// <summary>
        /// Validate DateTimePicker as Birthday, support mininum age and maximum age
        /// </summary>
        /// <param name="control">DateTimePicker to validate</param>
        /// <param name="minAge">Minimum age allowed</param>
        /// <param name="maxAge">Maximum age allowed</param>
        public void ValidateBirthday(DateTimePicker control, int minAge, int maxAge)
        {
            ValidateBirthday(control, minAge, maxAge, null);
        }

        /// <summary>
        /// Validate DateTimePicker as Birthday, support mininum age and maximum age
        /// </summary>
        /// <param name="control">DateTimePicker to validate</param>
        /// <param name="minAge">Minimum age allowed</param>
        /// <param name="maxAge">Maximum age allowed</param>
        /// <param name="message">Message to for both require minimum and maximum age</param>
        /// <param name="minMessage">Message for requirement of minimum age</param>
        /// <param name="maxMessage">Message for requirement of maximum age</param>
        public void ValidateBirthday(DateTimePicker control, int minAge, int maxAge, string message)
        {
            CONTROL_TO_VALIDATE.Add(control);

            control.Validating += delegate(object sender, CancelEventArgs e)
            {
                if (!AutoValidate) return;
                DateTimePicker senderControl = (DateTimePicker)sender;
                DateTime selectedDate = senderControl.Value;
                double currentAge = DateTime.Now.Subtract(selectedDate).TotalDays / 365;

                if ((minAge > 0 && currentAge < minAge) ||
                    (maxAge > 0 && currentAge > maxAge))
                {

                    if (!StringLib.isValid(message))
                    {
                        if (minAge > 0 && maxAge > 0)
                            message = ValidateMessage.ValidateBirthday;
                        else if (minAge > 0)
                            message = ValidateMessage.ValidateBirthdayMin;
                        else if (maxAge > 0)
                            message = ValidateMessage.ValidateBirthdayMax;
                    }

                    message = message.Replace("[MIN]", minAge + "").Replace("[MAX]", maxAge + "");

                    ERROR_PROVIDER.SetError(senderControl, message);
                    IsFormValidated = false;
                }
                else
                {
                    ERROR_PROVIDER.SetError(senderControl, null);
                }
            };
        }

        #endregion

        #region ValidateMoney

        private bool _isValidatingText = false;

        /// <summary>
        /// Validate input money width min max value
        /// </summary>
        /// <param name="control">Control to validate</param>
        /// <param name="require">Require true: always check, false: check if not blank</param>
        /// <param name="minValue">minimum value</param>
        /// <param name="maxValue">maximum value</param>
        /// <param name="controlName">name for control to put in message</param>        
        public void ValidateMoney(Control control, bool require, double minValue, double maxValue, string controlName)
        {
            ValidateMoney(control, require, minValue, maxValue, controlName, null);
        }

        /// <summary>
        /// Validate input money width min max value
        /// </summary>
        /// <param name="control">Control to validate</param>
        /// <param name="require">Require true: always check, false: check if not blank</param>
        /// <param name="minValue">minimum value</param>
        /// <param name="maxValue">maximum value</param>
        /// <param name="controlName">name for control to put in message</param>
        /// <param name="message">Your custom message include [NAME] [MIN] [MAX]</param>
        public void ValidateMoney(Control control, bool require, double minValue, double maxValue, string controlName, string message)
        {
            CONTROL_TO_VALIDATE.Add(control);

            control.TextChanged += delegate(object sender, EventArgs e)
            {
                if (_isValidatingText)
                    return;

                _isValidatingText = true;

                Control _control = (Control)sender;
                bool isTextBox = FormLib.matchControlType(_control, ControlType.TextBox);
                bool isCombobox = FormLib.matchControlType(_control, ControlType.ComboBox);

                int SelectionStart = 0;
                int CurrentLength = control.Text.Length;
                if (isCombobox)
                    SelectionStart = ((ComboBox)_control).SelectionStart;
                else if (isTextBox)
                    SelectionStart = ((TextBox)_control).SelectionStart;

                _control.Text = NumberLib.getDouble(_control.Text).ToString("#,##0.##");
                SelectionStart -= CurrentLength - _control.Text.Length;
                if (SelectionStart < 0) SelectionStart = 0;
                if (SelectionStart > _control.Text.Length) SelectionStart = _control.Text.Length;

                if (isCombobox)
                    ((ComboBox)_control).SelectionStart = SelectionStart;
                else if (isTextBox)
                    ((TextBox)_control).SelectionStart = SelectionStart;

                _isValidatingText = false;
            };

            control.Validating += delegate(object sender, CancelEventArgs e)
            {
                if (!AutoValidate) return;
                Control senderControl = (Control)sender;
                senderControl.Text = senderControl.Text.Trim();
                double objValue = NumberLib.getDouble(senderControl.Text);
                bool isErrorMinValue = (minValue >= 0 && objValue < minValue);
                bool isErrorMaxValue = (maxValue >= 0 && objValue > maxValue);
                bool isErrorMaxMin = isErrorMinValue || isErrorMaxValue;

                if ((require && isErrorMaxMin) || (!require && objValue > 0 && isErrorMaxMin))
                {

                    if (!StringLib.isValid(message))
                    {
                        if (minValue >= 0 && maxValue >= 0)
                            message = ValidateMessage.ValidateMoney;
                        else if (minValue > 0)
                            message = ValidateMessage.ValidateMoneyMin;
                        else if (maxValue > 0)
                            message = ValidateMessage.ValidateMoneyMax;
                    }

                    if (!StringLib.isValid(controlName)) controlName = "số tiền";
                    message = message.Replace("[MIN]", minValue + "").Replace("[MAX]", maxValue + "").Replace("[NAME]", controlName);


                    ERROR_PROVIDER.SetError(senderControl, message);
                    IsFormValidated = false;
                }
                else
                {
                    ERROR_PROVIDER.SetError(senderControl, null);

                }
            };
        }
        #endregion

        #region ValidateNumber

        public void InputNumberOnly(Control control)
        {
            control.KeyDown += delegate(object sender, KeyEventArgs e)
            {
                // if the keys is out of the accepted keys, simply ignor it
                if (((e.KeyCode < Keys.D0) || (e.KeyCode > Keys.D9)) &&
                        ((e.KeyCode < Keys.NumPad0) || (e.KeyCode > Keys.NumPad9)) &&
                        (e.KeyCode != Keys.Left) && (e.KeyCode != Keys.Right) &&
                        (e.KeyCode != Keys.Back) && (e.KeyCode != Keys.Delete) &&
                        (e.KeyCode != Keys.Home) && (e.KeyCode != Keys.End) && (e.KeyCode != Keys.Shift))
                    e.SuppressKeyPress = true;
            };
        }

        private bool _isValidatingNumber = false;

        /// <summary>
        /// Validate input number width min max value
        /// </summary>
        /// <param name="control">Control to validate</param>
        /// <param name="require">Require true: always check, false: check if not blank</param>
        /// <param name="minValue">minimum value</param>
        /// <param name="maxValue">maximum value</param>
        /// <param name="controlName">name for control to put in message</param>        
        public void ValidateNumber(Control control, bool require, double minValue, double maxValue, string controlName)
        {
            ValidateNumber(control, require, 0, minValue, maxValue, controlName, null);
        }

        /// <summary>
        /// Validate input number width min max value
        /// </summary>
        /// <param name="control">Control to validate</param>
        /// <param name="require">Require true: always check, false: check if not blank</param>
        /// <param name="minValue">minimum value</param>
        /// <param name="maxValue">maximum value</param>
        /// <param name="controlName">name for control to put in message</param>
        /// <param name="message">Your custom message include [NAME] [MIN] [MAX]</param>
        public void ValidateNumber(Control control, bool require, int nFloat, double minValue, double maxValue, string controlName, string message = null )
        {
            CONTROL_TO_VALIDATE.Add(control);

            control.TextChanged += delegate(object sender, EventArgs e)
            {
                if (_isValidatingNumber)
                    return;

                _isValidatingNumber = true;

                Control _control = (Control)sender;
                bool isTextBox = FormLib.matchControlType(_control, ControlType.TextBox);
                bool isCombobox = FormLib.matchControlType(_control, ControlType.ComboBox);

                int SelectionStart = 0;
                int CurrentLength = control.Text.Length;
                if (isCombobox)
                    SelectionStart = ((ComboBox)_control).SelectionStart;
                else if (isTextBox)
                    SelectionStart = ((TextBox)_control).SelectionStart;

                string format = "#,##0";
                if (nFloat > 0)
                {
                    format += ".";
                    for (int i = 0; i < nFloat - 1; i++) format += "#";
                    format += "0";
                }
                _control.Text = NumberLib.getDouble(_control.Text).ToString(format);
                SelectionStart -= CurrentLength - _control.Text.Length;
                if (SelectionStart < 0) SelectionStart = 0;
                if (SelectionStart > _control.Text.Length) SelectionStart = _control.Text.Length;

                if (isCombobox)
                    ((ComboBox)_control).SelectionStart = SelectionStart;
                else if (isTextBox)
                    ((TextBox)_control).SelectionStart = SelectionStart;

                _isValidatingNumber = false;
            };

            control.Validating += delegate(object sender, CancelEventArgs e)
            {
                if (!AutoValidate) return;
                Control senderControl = (Control)sender;
                senderControl.Text = senderControl.Text.Trim();
                double objValue = NumberLib.getDouble(senderControl.Text);
                bool isErrorMinValue = (minValue >= 0 && objValue < minValue);
                bool isErrorMaxValue = (maxValue >= 0 && objValue > maxValue);
                bool isErrorMaxMin = isErrorMinValue || isErrorMaxValue;

                if ((require && isErrorMaxMin) || (!require && objValue > 0 && isErrorMaxMin))
                {

                    if (!StringLib.isValid(message))
                    {
                        if (minValue >= 0 && maxValue >= 0)
                            message = ValidateMessage.ValidateNumber;
                        else if (minValue > 0)
                            message = ValidateMessage.ValidateNumberMin;
                        else if (maxValue > 0)
                            message = ValidateMessage.ValidateNumberMax;
                    }

                    if (!StringLib.isValid(controlName)) controlName = "giá trị";
                    message = message.Replace("[MIN]", minValue + "").Replace("[MAX]", maxValue + "").Replace("[NAME]", controlName);


                    ERROR_PROVIDER.SetError(senderControl, message);
                    IsFormValidated = false;
                }
                else
                {
                    ERROR_PROVIDER.SetError(senderControl, null);

                }
            };
        }
        #endregion

        #region ValidatePhone
        /// <summary>
        /// Validate control that store phone number (telephone and mobiphone)
        /// </summary>
        /// <param name="control">Control to validate, all controls that have Text property</param>
        /// <param name="require">True if require value otherwise require only if Text not blank</param>
        /// <param name="minLength">Minimum length requirement, -1 if not require minimum length</param>
        /// <param name="maxLength">Maximum length requirement, -1 if not require maximum length</param>
        /// <param name="isMobilephone">True if require as an mobiphone begin with 0</param>
        public void ValidatePhone(Control control, bool require, int minLength, int maxLength, bool isMobilephone)
        {
            ValidatePhone(control, require, minLength, maxLength, isMobilephone, null);
        }

        /// <summary>
        /// Validate control that store phone number (telephone and mobiphone)
        /// </summary>
        /// <param name="control">Control to validate, all controls that have Text property</param>
        /// <param name="require">True if require value otherwise require only if Text not blank</param>
        /// <param name="minLength">Minimum length requirement, -1 if not require minimum length</param>
        /// <param name="maxLength">Maximum length requirement, -1 if not require maximum length</param>
        /// <param name="isMobilephone">True if require as an mobiphone begin with 0</param>
        /// <param name="message">Custom message if message is not null or blank</param>
        public void ValidatePhone(Control control, bool require, int minLength, int maxLength, bool isMobilephone, string message)
        {
            CONTROL_TO_VALIDATE.Add(control);

            control.TextChanged += delegate(object sender, EventArgs e)
            {
                Control _control = (Control)sender;
                bool isTextBox = FormLib.matchControlType(_control, ControlType.TextBox);
                bool isCombobox = FormLib.matchControlType(_control, ControlType.ComboBox);


                char[] chars = _control.Text.ToCharArray();
                for (int i = 0; i < _control.Text.Length; i++)
                {
                    int code;
                    code = Convert.ToInt16(chars[i]);
                    if ((code > 58 || code < 48))
                    {
                        _control.Text = _control.Text.Remove(i, 1);

                        if (isCombobox)
                            ((ComboBox)_control).SelectionStart = _control.Text.Length;
                        else if (isTextBox)
                            ((TextBox)_control).SelectionStart = _control.Text.Length;
                    }
                }
            };

            control.Validating += delegate(object sender, CancelEventArgs e)
            {
                if (!AutoValidate) return;
                Control senderControl = (Control)sender;
                senderControl.Text = senderControl.Text.Trim();

                if (!IsValidLength(senderControl.Text, require, minLength, maxLength))
                {
                    if (!StringLib.isValid(message))
                        message = ValidateMessage.ValidatePhone;

                    ERROR_PROVIDER.SetError(senderControl, message);
                    IsFormValidated = false;
                }
                else if (isMobilephone && senderControl.Text.Length > 0 && !senderControl.Text.StartsWith("0"))
                {
                    if (!StringLib.isValid(message))
                        message = ValidateMessage.ValidatePhoneMobile;

                    ERROR_PROVIDER.SetError(senderControl, message);
                    IsFormValidated = false;
                }
                else
                {
                    ERROR_PROVIDER.SetError(senderControl, null);

                }
            };
        }
        #endregion

        #region ValidateText

        /// <summary>
        /// Validate Text value of any control have Text property
        /// </summary>
        /// <param name="control">Any control have Text property</param>
        /// <param name="require">True if require value otherwise require only if Text not blank</param>
        /// <param name="minLength">Minimum length requirement, -1 if not require minimum length</param>
        /// <param name="maxLength">Maximum length requirement, -1 if not require maximum length</param>
        /// <param name="message">Custom message if message is not null or blank</param>
        public void ValidateText(Control control, bool require, int minLength, int maxLength, string message = null)
        {
            CONTROL_TO_VALIDATE.Add(control);

            control.Validating += delegate(object sender, CancelEventArgs e)
            {
                if (!AutoValidate) return;
                Control senderControl = (Control)sender;
                senderControl.Text = senderControl.Text.Trim();

                if (!IsValidLength(senderControl.Text, require, minLength, maxLength))
                {
                    if (!StringLib.isValid(message))
                    {
                        if (minLength > 0 && maxLength > 0)
                            message = ValidateMessage.ValidateText;
                        else if (minLength > 0)
                            message = ValidateMessage.ValidateTextMin;
                        else if (maxLength > 0)
                            message = ValidateMessage.ValidateTextMax;
                    }

                    message = message.Replace("[MIN]", minLength + "").Replace("[MAX]", maxLength + "");

                    ERROR_PROVIDER.SetError(senderControl, message);
                    IsFormValidated = false;
                }
                else
                {
                    ERROR_PROVIDER.SetError(senderControl, null);
                }
            };
        }
        #endregion

        #region ValidateEmail
        /// <summary>
        /// Validate control to accept email address only
        /// </summary>
        /// <param name="control">Any control have Text property</param>
        public void ValidateEmail(Control control, bool require)
        {
            ValidateEmail(control, require, null);
        }

        /// <summary>
        /// Validate control to accept email address only
        /// </summary>
        /// <param name="control">Any control have Text property</param>
        /// <param name="message">Custom message if message is not null or blank</param>
        public void ValidateEmail(Control control, bool require, string message)
        {
            CONTROL_TO_VALIDATE.Add(control);

            control.Validating += delegate(object sender, CancelEventArgs e)
            {
                if (!AutoValidate) return;
                Control senderControl = (Control)sender;
                senderControl.Text = senderControl.Text.Trim();

                if ((require || StringLib.isValid(senderControl.Text)) && !IsEmail(senderControl.Text))
                {
                    if (!StringLib.isValid(message))
                        message = ValidateMessage.ValidateEmail;

                    ERROR_PROVIDER.SetError(senderControl, message);
                    IsFormValidated = false;
                }
                else
                {
                    ERROR_PROVIDER.SetError(senderControl, null);
                }
            };
        }


        #endregion

        #region Common function
        public bool IsValidLength(string content, bool require, int minLength, int maxLength)
        {
            if (require || StringLib.isValid(content))
            {
                content = content.Trim();
                if (minLength >= 0 && content.Length < minLength)
                {
                    return false;
                }
                else if (maxLength >= 0 && content.Length > maxLength)
                {
                    return false;
                }
                else if (minLength < 0 && maxLength < 0 && content.Length == 0)
                {
                    return false;
                }
                return true;
            }
            return true;
        }

        public bool IsEmail(string email)
        {
            Regex emailregex = new Regex(@"[a-zA-Z0-9_\-\.]+@[a-zA-Z0-9_\-\.]+\.[a-zA-Z]{2,5}");
            Match m = emailregex.Match(email);
            return m.Success;
        }
        #endregion

        #region Custome validation
        public delegate bool CustomValidation();
        public delegate ReturnSet CustomValidationMessage();

        /// <summary>
        /// Add custom validate and with one message
        /// </summary>
        /// <param name="control"></param>
        /// <param name="function"></param>
        /// <param name="message"></param>
        public void ValidateCustomControl(Control control, CustomValidation function, string message)
        {
            CONTROL_TO_VALIDATE.Add(control);

            control.Validating += delegate(object sender, CancelEventArgs e)
            {
                if (!AutoValidate) return;
                Control senderControl = (Control)sender;

                if (!function())
                {
                    ERROR_PROVIDER.SetError(senderControl, message);
                    IsFormValidated = false;
                }
                else
                {
                    ERROR_PROVIDER.SetError(senderControl, null);
                }
            };
        }

        /// <summary>
        /// Add custom validation and dynamic message
        /// </summary>
        /// <param name="control"></param>
        /// <param name="function"></param>
        public void ValidateCustomControl(Control control, CustomValidationMessage function)
        {
            CONTROL_TO_VALIDATE.Add(control);

            control.Validating += delegate(object sender, CancelEventArgs e)
            {
                if (!AutoValidate) return;
                Control senderControl = (Control)sender;

                ReturnSet result = function();

                if (!result.Success)
                {
                    ERROR_PROVIDER.SetError(senderControl, result.Message);
                    IsFormValidated = false;
                }
                else
                {
                    ERROR_PROVIDER.SetError(senderControl, null);
                }
            };
        }
        #endregion

        #region ValidateFromToDate
        public void ValidateFromToDate(DateTimePicker fromDate, DateTimePicker toDate, string message)
        {
            ValidateFromToDate(fromDate, toDate, true, message);
        }
        public void ValidateFromToDate(DateTimePicker fromDate, DateTimePicker toDate, bool allowEqual, string message)
        {
            CONTROL_TO_VALIDATE.Add(toDate);

            toDate.Validating += delegate(object sender, CancelEventArgs e)
            {
                if (!AutoValidate) return;
                Control senderControl = (Control)sender;

                if (fromDate.Value > toDate.Value || (!allowEqual && fromDate.Value == toDate.Value))
                {
                    ERROR_PROVIDER.SetError(senderControl, message);
                    IsFormValidated = false;
                }
                else
                {
                    ERROR_PROVIDER.SetError(senderControl, null);
                }
            };
        }
        #endregion

        public void SetError(Control ctrl, string message)
        {
            ERROR_PROVIDER.SetError(ctrl, message);
            this.IsFormValidated = false;
        }

        #endregion
    }

    public class ValidateMessageSet {

        public string ValidateGroupRadioButton { get; set; }
        public string ValidateGroupCheckBox { get; set; }
        public string ValidateCheckedListBox { get; set; }
        public string ValidateListBox { get; set; }
        public string ValidateCombobox { get; set; }
        public string ValidateBirthday { get; set; }
        public string ValidateBirthdayMin { get; set; }
        public string ValidateBirthdayMax { get; set; }
        public string ValidatePhone { get; set; }
        public string ValidatePhoneMobile { get; set; }
        public string ValidateText { get; set; }
        public string ValidateTextMin { get; set; }
        public string ValidateTextMax { get; set; }
        public string ValidateEmail { get; set; }
        public string ValidateMoney { get; set; }
        public string ValidateMoneyMin { get; set; }
        public string ValidateMoneyMax { get; set; }
        public string ValidateNumber { get; set; }
        public string ValidateNumberMin { get; set; }
        public string ValidateNumberMax { get; set; }

        public ValidateMessageSet()
        {
        }

        public ValidateMessageSet English()
        {
            ValidateGroupRadioButton = "Please check at least one item";
            ValidateGroupCheckBox = "Please check at least [MIN] item";
            ValidateCheckedListBox = "Please check at least [MIN] item";
            ValidateListBox = "Please select at least [MIN] item";
            ValidateCombobox = "Please select one item";
            ValidateBirthday = "Your age is must between [MIN] and [MAX]";
            ValidateBirthdayMin = "Your age is must greater than [MIN]";
            ValidateBirthdayMax = "Your age is must lower than [MAX]";
            ValidatePhone = "Please enter phone number";
            ValidatePhoneMobile = "Please enter mobile phone number begin with 0";
            ValidateText = "Please enter at least [MIN] letters and at most [MAX] letters";
            ValidateTextMin = "Please enter at least [MIN] letters";
            ValidateTextMax = "Please enter at most [MAX] letters";
            ValidateEmail = "Please enter email address";
            ValidateMoney = "Xin vui lòng nhập [NAME] từ [MIN] đến [MAX]";
            ValidateMoneyMin = "Xin vui lòng nhập [NAME] ít nhất là [MIN]";
            ValidateMoneyMax = "Xin vui lòng nhập [NAME] không vượt quá [MAX]";
            ValidateNumber = "Xin vui lòng nhập [NAME] từ [MIN] đến [MAX]";
            ValidateNumberMin = "Xin vui lòng nhập [NAME] ít nhất là [MIN]";
            ValidateNumberMax = "Xin vui lòng nhập [NAME] không vượt quá [MAX]";
            return this;
        }

        public ValidateMessageSet Vietnamese()
        {
            ValidateGroupRadioButton = "Xin vui lòng đánh dấu vào một lựa chọn";
            ValidateGroupCheckBox = "Xin vui lòng đánh dấu ít nhất [MIN] lựa chọn";
            ValidateCheckedListBox = "Xin vui lòng đánh dấu ít nhất [MIN] lựa chọn";
            ValidateListBox = "Xin vui lòng chọn ít nhất [MIN] lựa chọn";
            ValidateCombobox = "Xin vui lòng chọn một lựa chọn trong danh sách";
            ValidateBirthday = "Tuổi hợp lệ phải từ [MIN] đến [MAX] tuổi";
            ValidateBirthdayMin = "Tuổi hợp lệ phải lớn hơn [MIN] tuổi";
            ValidateBirthdayMax = "Tuổi hợp lệ phải nhỏ hơn [MAX] tuổi";
            ValidatePhone = "Xin vui lòng nhập một số điện thoại";
            ValidatePhoneMobile = "Xin vui lòng nhập một số điện thoại di động hợp lệ (bắt đầu bằng số 0";
            ValidateText = "Xin vui lòng nhập từ [MIN] đến [MAX] ký tự";
            ValidateTextMin = "Xin vui lòng nhập ít nhất [MIN] ký tự";
            ValidateTextMax = "Xin vui lòng nhập nhiều nhất là [MAX] ký tự";
            ValidateEmail = "Xin vui lòng nhập địa chị email";
            ValidateMoney = "Xin vui lòng nhập [NAME] từ [MIN] đến [MAX]";
            ValidateMoneyMin = "Xin vui lòng nhập [NAME] ít nhất là [MIN]";
            ValidateMoneyMax = "Xin vui lòng nhập [NAME] không vượt quá [MAX]";
            ValidateNumber = "Xin vui lòng nhập [NAME] từ [MIN] đến [MAX]";
            ValidateNumberMin = "Xin vui lòng nhập [NAME] ít nhất là [MIN]";
            ValidateNumberMax = "Xin vui lòng nhập [NAME] không vượt quá [MAX]";
            return this;
        }
    }
	
    
}
